<template>
	<div class="musicPlay">
		<audio
			ref="audioRef"
			@error="dealError"
			@canplay="checkPlay"
			@timeupdate="updateTime"
			@play="state.isPlaying = true"
			@pause="state.isPlaying = false"
		>
			<source :src="musicUrl" type="audio/mpeg" />
		</audio>

		<div class="audio-panel">
			<el-avatar :size="250">
				<img
					:src="albumImage || DEFAULT_IMG"
					:style="{
						animation: `RotateAlbum ${6 / state.playSpeed}s linear infinite`,
						animationPlayState: state.isPlaying ? 'running' : 'paused',
					}"
				/>
			</el-avatar>
			<div class="music-header">
				<p class="music-name">{{ musicName }}</p>
				<p class="music-timetip">
					{{ formatCurrentTime }}/{{ formatDuration }}
				</p>
			</div>

			<div
				class="control-box"
				@mousedown="state.isDraging = true"
				@mouseup="state.isDraging = false"
			>
				<el-slider
					v-model="state.playProcess"
					class="sliderClass"
					@change="setProcess"
					:format-tooltip="formatTooltip"
				></el-slider>
			</div>
			<div class="playControl">
				<span class="audioSpan" @click="clickPlayer('backward')">
					<el-icon><DArrowLeft /></el-icon>
				</span>

				<span
					class="audioSpan"
					@click="clickPlayer('play')"
					v-show="!state.isPlaying"
				>
					<el-icon><VideoPlay /></el-icon>
				</span>
				<span
					class="audioSpan"
					@click="clickPlayer('pause')"
					v-show="state.isPlaying"
				>
					<el-icon><VideoPause /></el-icon>
				</span>
				<span class="audioSpan" @click="clickPlayer('forward')">
					<el-icon><DArrowRight /></el-icon>
				</span>

				<span class="audioSpan" @click="clickPlayer('refresh')">
					<el-icon><Refresh /></el-icon>
				</span>

				<el-slider
					v-model="state.playVolume"
					class="sliderVolumClass"
					:format-tooltip="formatTooltipVol"
					@change="setVolume"
				></el-slider>
			</div>
		</div>
	</div>
</template>

<script lang="ts" setup>
import { ref, computed, reactive, defineProps } from "vue";
import {
	VideoPause,
	VideoPlay,
	Refresh,
	DArrowLeft,
	DArrowRight,
} from "@element-plus/icons-vue";

import DEFAULT_IMG from "@/assets/img/default-album.png";

defineProps({
	musicUrl: {
		type: String,
		default: "",
	},
	albumImage: {
		type: String,
		default: "",
	},
	musicName: {
		type: String,
		default: "未知音乐格式文件",
	},
});

const audioRef = ref(null as unknown as HTMLAudioElement);

const state = reactive({
	playSpeed: 1,
	playProcess: 0,
	isError: false,
	playVolume: 100,
	isDraging: false,
	isPlaying: false,
	totalTimes: "00:00",
	currentTime: "00:00",
});

const formatDuration = computed(() => {
	if (typeof state.totalTimes == "number") {
		const time = Math.floor(state.totalTimes);
		const min = Math.floor(time / 60);
		const sec = time % 60;
		return `${formatTime(min)}:${formatTime(sec)}`;
	}
	return "00:00";
});

const formatCurrentTime = computed(() => {
	if (typeof state.currentTime == "number") {
		const time = Math.floor(state.currentTime);
		const min = Math.floor(time / 60);
		const sec = time % 60;
		return `${formatTime(min)}:${formatTime(sec)}`;
	}
	return "00:00";
});

function formatTime(param: number) {
	if (param > 9) {
		return param + "";
	} else {
		return "0" + param;
	}
}

function formatTooltip(val: number) {
	const time = Math.floor((val / 100) * (state.totalTimes as any));
	const min = Math.floor(time / 60);
	const sec = time % 60;
	return `${formatTime(min)}:${formatTime(sec)}`;
}

function formatTooltipVol(vol: number) {
	const val = Math.round(((vol * 2) / 100) * 10) * 5;
	return `音量：${val}%`;
}

function clickPlayer(
	command: "play" | "pause" | "backward" | "forward" | "refresh"
) {
	switch (command) {
		case "play": {
			state.isPlaying = !state.isPlaying;
			audioRef.value.play();
			break;
		}

		case "pause": {
			state.isPlaying = !state.isPlaying;
			audioRef.value.pause();
			break;
		}

		case "backward": {
			if (state.playSpeed > 0.5) {
				state.playSpeed -= 0.5;
				audioRef.value.playbackRate = state.playSpeed;
			}
			break;
		}

		case "forward": {
			if (state.playSpeed < 2) {
				state.playSpeed += 0.5;
				audioRef.value.playbackRate = state.playSpeed;
			}
			break;
		}

		case "refresh": {
			state.playSpeed = 1;
			audioRef.value.playbackRate = 1;
			audioRef.value.load();
			break;
		}
	}
}

function setProcess(val: number) {
	audioRef.value.currentTime = Math.round(
		(val / 100) * Number(state.totalTimes)
	);
	audioRef.value.play();
}
function setVolume(vol: number) {
	audioRef.value.volume = Math.round((vol / 100) * 10) / 10;
}

function updateTime(e: any) {
	if (!state.isDraging) {
		state.playProcess = (e.target.currentTime / Number(state.totalTimes)) * 100;
		state.currentTime = e.target.currentTime;
	}
}

function checkPlay(e: any) {
	state.isError = false;
	audioRef.value.volume = 0.5;
	state.totalTimes = e.target.duration;
}

function dealError() {
	state.isError = true;
}
</script>

<style lang="less">
.musicPlay {
	display: flex;
	margin-top: 40px;
	justify-content: center;
	.control-box {
		display: flex;
		align-items: center;
		justify-content: space-between;
	}

	.el-avatar {
		display: flex;
		margin: 0 auto;
		margin-top: 35px;
		justify-content: center;

		@keyframes RotateAlbum {
			0% {
				transform: rotate(0deg);
			}

			50% {
				transform: rotate(180deg);
			}

			100% {
				transform: rotate(360deg);
			}
		}
	}

	.audio-panel {
		width: 700px;
		border-radius: 6px;
		padding: 10px 24px;
		border-radius: 2px;
		background-color: #fff;
		border: 1px dashed #d9d9d9;
		box-shadow: 0 10px 16px 0 rgb(0 0 0 / 20%);

		.el-avatar {
			box-shadow: 0 6px 20px 0 rgb(0 0 0 / 19%);
		}

		.music-header {
			display: flex;
			flex-direction: row;
			align-items: center;
			justify-content: space-between;

			p.music-timetip {
				color: #409eff;
				font-size: 13px;
				white-space: nowrap;
			}
		}

		.playControl {
			display: flex;
			margin-top: 30px;
			user-select: none;
			align-items: center;
			padding-bottom: 20px;

			@media screen and (max-width: 476px) {
				justify-content: center;
			}

			.sliderVolumClass {
				display: flex;
				@media screen and (max-width: 476px) {
					display: none;
				}
			}

			.audioSpan {
				font-size: 20px;

				margin-right: 30px;
				@media screen and (max-width: 476px) {
					margin-left: 15px;
					margin-right: 15px;
				}
				cursor: pointer;
				&:hover {
					color: #409eff;
				}
				.audioIcon {
					font-size: 28px;
				}
				.speed {
					font-size: 16px;
				}
				.volume {
					font-size: 18px;
				}
			}
		}
	}
}
</style>
